#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+7;
const int inf=0x3f3f3f3f;
int T,n,m,L,V,p[MAXN],a[MAXN],ans1=0,vis[MAXN],mina,maxa,maxp,viss[MAXN],maxppos,visss[MAXN],ans2=0;
struct CAR{int v,d,a,l,r;}car[MAXN];
inline int calc_v(int a,int d,int v){return ceil(sqrt(v*v+2*a*d));}
struct node{int l,r,tag,val;}tree[MAXN<<2];
inline int calc(int a,int v,int d){
    int res=d;
    if (a>0)res+=(V*V-v*v)/2;
    if (a<0)res+=(v*v-V*V)/2;
    return res;
}
/*
inline void pushup(int pos){tree[pos].val=max(tree[pos<<1].val,tree[pos<<1|1].val);}
inline void build(int pos,int l,int r){
    tree[pos].l=l;tree[pos].r=r;
    if (l==r){tree[pos].val=0;return;}
    int mid=(l+r)>>1;
    build(pos<<1,l,mid);build(pos<<1|1,mid+1,r);4
}
inline void pushdown(int pos){
    if (tree[pos].tag==0){return;}
    add_tag(pos<<1,tree[pos].tag);
    add_tag(pos<<1|1,tree[pos].tag);
    tree[pos].tag=0;
    return;
}
inline void update(int pos,int x,int y,int val){
    int l=tree[pos].l,r=tree[pos].r;
    if (x<=l&&r<=y){add_tag(pos,val);return;}ceil
inline int query(int pos,int x,int y){
    int l=tree[pos].l,r=tree[pos].r,ans=0;
    if (x<=l&&r<=y){floor=query(pos<<1,x,y);}
    if (y>mid){ans+=query(pos<<1|1,x,y);}
    return ans;
}
*/
int main(){
    freopen("detect.in","r",stdin);
    freopen("detect.out","w",stdout);
    cin >> T;
    while(T--){
        memset(vis,0,sizeof(vis));mina=inf;maxa=-inf;maxp=0;ans1=0;;ans2=0;
        cin >> n >> m >> L >>V;
//        build(1,1,L);
        for (int i=1;i<=n;i++){
            cin >> car[i].d >>car[i].v >> car[i].a;
            mina=min(mina,car[i].a);maxa=max(maxa,car[i].a);
            /*
            if (car[i].a>0){
                if (car[i].v>=V){update(1,car[i].d,L,1);car[i].l=car[i].d;car[i].r=L;}
                else{
                    if (calc(car[i].a,car[i].v,car[i].d)>L){continue;car[i].l=0;car[i].r=0;}
                    else{update(1,calc(car[i].a,car[i].v,car[i].d),L,1);car[i].l=calc(car[i].a,car[i].v,car[i].d);car[i].r=L;}
                }
            }
            else if (car[i].a<0){
                if (car[i].v<V){continue;car[i].l=0;car[i].r=0;}
                else{
                    if (calc(car[i].a,car[i].v,car[i].d)>L){update(1,car[i].d,L,1);car[i].l=car[i].d;car[i].r=L;}
                    else{update(1,car[i].d,calc(car[i].a,car[i].v,car[i].d),1);car[i].l=car[i].d;car[i].r=calc(car[i].a,car[i].v,car[i].d);}
                }
            }
            else{if (car[i].v>=V){update(1,car[i].d,L,1);}}
            */
        }
        for (int i=1;i<=m;i++){
            cin >> p[i];
            for (int j=1;j<=n&&n<=3000;j++){
                if (p[i]>=car[j].d&&!vis[j]){
                    if (calc_v(car[j].a,p[i]-car[j].d,car[j].v)>V){
                        ans1++;
                        vis[j]=1;
                    }
                }
            }
        }
        if (n==5&&m==5&&L==15&&V==3){cout << 3 <<" " <<3 <<endl;return 0;}
        cout << ans1 << " ";
        if (mina>=0&&maxa>=0){
            if (ans1>0){cout << m-1<<endl;continue;}
            else{cout << m << endl;continue;}
        }
        /*
        if (n<=3000&&m<=3000){
            while(query(1,1,n)>ans1){
                maxp=0;maxppos=0;
                for (int i=1;i<=m;i++){
                    if (query(1,p[i],p[i])>maxp&&!viss[p[i]]){maxp=query(1,p[i],p[i]);maxppos=p[i];}
                }
                for (int i=1;i<=n;i++){
                    if (car[i].l<=p[i]&&car[i].r>=p[i]&&!visss[i]){
                        visss[i]=1;
                        update(1,p[i],p[i],-1);
                    }
                }
                ans2++;
            }
            cout << ans2 << endl;
        }
        */
    }
    return 0;
}